﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows.Forms;
using System.ComponentModel;
using System.Globalization;
using System.IO;
using GeoAPI.Geometries;
using GeoAPI.IO;
using NetTopologySuite.Geometries;
using NetTopologySuite.Features;
using NetTopologySuite.IO;

using SpectationClient.GUI;
using SpectationClient.Stuff;
using SpectationClient.DataBaseDescription;
using System.Xml;

namespace SpectationClient.DGVExtensions {

    public class DataGridViewGeometryColumn : DataGridViewExtensionBaseColumn {
        public int srid { get; set; }



        public override DataBaseDescription.TableInfo TableInfo {
            get { return this.ColumnInfo == null? null : this.ColumnInfo.Table; }
        }

        protected new ColumnInfoGeometry columnInfo;
        public new ColumnInfoGeometry ColumnInfo {
            get {
                return this.columnInfo;
            }
        }
        public DataGridViewGeometryColumn(int srid){
            this.srid = srid;
            this.CellTemplate = new DataGridViewGeometryCell();
            this.ToolTipText = "Add new Points as Well-Kown-Text,\n e.g. POINT(42.234 74.234)";

            this.ContextMenuStrip = new ContextMenuStrip();
            ToolStripMenuItem labelSHP = new ToolStripMenuItem("Speichere als Shapefile");
            ToolStripMenuItem labelKML = new ToolStripMenuItem("Speichere als KML Datei");
            // labelShow.Width = 150;
            labelSHP.Click += new EventHandler(labelSHP_Click);
            labelKML.Click += new EventHandler(labelKML_Click);
            this.ContextMenuStrip.Items.Add(labelSHP);
            this.ContextMenuStrip.Items.Add(labelKML);
        }

        void labelSHP_Click(object sender, EventArgs e) {

            this.DataGridView.Cursor = Cursors.WaitCursor;
            SaveFileDialog SFD = new SaveFileDialog();
            SFD.Title = "Speichere Shapefile";
            SFD.Filter = "Shapefile (*.shp)|*.shp";
            SFD.AddExtension = false;
            SFD.DefaultExt = ".shp";
            SFD.FileName = "koordinaten";

            if(SFD.ShowDialog() == DialogResult.OK) {
                FileInfo fiSHP = new FileInfo(SFD.FileName);
                this.saveDGVasSHP(fiSHP);
            }

            this.DataGridView.Cursor = Cursors.Default;
        }

        void labelKML_Click(object sender, EventArgs e) {

            this.DataGridView.Cursor = Cursors.WaitCursor;
            SaveFileDialog SFD = new SaveFileDialog();
            SFD.Title = "Speichere KML Datei";
            SFD.Filter = "Keyhole Markup Language (*.kml)|*.kml";
            SFD.AddExtension = true;
            SFD.DefaultExt = ".kml";
            SFD.FileName = "koordinaten";

            if(SFD.ShowDialog() == DialogResult.OK){
                FileInfo fiKML = new FileInfo(SFD.FileName);
                this.saveDGVasKML(fiKML);
            }
            
            this.DataGridView.Cursor = Cursors.Default;
        }


        public void saveDGVasSHP(FileInfo shpFile, String[] infoColumns = null, bool selectedOnly=true) {
            if(infoColumns == null) {
                infoColumns = (from DataGridViewColumn c in this.DataGridView.Columns
                               where c.ValueType != typeof(Byte[]) &&
                                    c.ValueType != typeof(Object)
                               select c.Name).ToArray();

            };

            String basename = Regex.Replace(shpFile.FullName, @"\.shp$", "", RegexOptions.IgnoreCase);
            
            
            try {

                ShapefileDataWriter SFD = new ShapefileDataWriter(basename);
                ShapefileWriter SFW = new ShapefileWriter();
                List<Feature> featureCollection = new List<Feature>();
             
                foreach(DataGridViewRow row in this.DataGridView.Rows) {
                    DataGridViewGeometryCell GCell = row.Cells[this.Index] as DataGridViewGeometryCell;
                    if(GCell == null || GCell.Geometry == null) continue;
                    if(selectedOnly && !(row.Selected || GCell.Selected)) continue;

                    IGeometry g = GCell.Geometry;
                    
                    AttributesTable attributes = new AttributesTable();
                    String[] cnames = (from DataGridViewColumn c in this.DataGridView.Columns select c.Name).ToArray();

                    foreach(DataGridViewColumn c in this.DataGridView.Columns){
                        if(c.ValueType == typeof(Byte[]) || c.ValueType == typeof(Object)) continue;
                        String name = c.Name;
                        Object value = row.Cells[c.Index].Value;
                        
                        //Remove non-ascii characters
                        if(value is String) value = Regex.Replace(value as String, @"[^\u0000-\u007F]", string.Empty);
                        
                        attributes.AddAttribute(c.Name, value);

                    }
                 
                    featureCollection.Add(new Feature(g, attributes));

                }

                DbaseFileHeader DBFHeader = this.GetHeader(featureCollection[0], featureCollection.Count);
                SFD.Header = DBFHeader;
                SFD.Write(featureCollection);

            } catch(Exception ex) {
                FormHelper.ShowErrorBox(ex);
            }
        
        }

        /// <summary>
        /// Gets the stub header.
        /// </summary>
        /// <param name="feature">The feature.</param>
        /// <param name="count">The count.</param>
        /// <returns></returns>
        private DbaseFileHeader GetHeader(Feature feature, int count) {
            IAttributesTable attribs = feature.Attributes;
            String[] attrNames = attribs.GetNames();
            String[] colNames = (from DataGridViewColumn c in this.DataGridView.Columns select c.Name).ToArray();
            DbaseFileHeader header = new DbaseFileHeader();
            header.NumRecords = count;
            header.Encoding = ASCIIEncoding.Default;
            foreach(String name in colNames) {
                if(!attribs.Exists(name)) continue;

                Type type = attribs.GetType(name);
                if(type == typeof(double) || type == typeof(float) || type == typeof(Decimal))
                    header.AddColumn(name, 'N', DoubleLength, DoubleDecimals);
                else if(type == typeof(short) || type == typeof(ushort) ||
                        type == typeof(int) || type == typeof(uint) ||
                        type == typeof(long) || type == typeof(ulong))

                    header.AddColumn(name, 'N', IntLength, IntDecimals);
                else if(type == typeof(string))
                    header.AddColumn(name, 'C', StringLength, StringDecimals);
                else if(type == typeof(bool))
                    header.AddColumn(name, 'L', BoolLength, BoolDecimals);
                else if(type == typeof(DateTime))
                    header.AddColumn(name, 'D', DateLength, DateDecimals);
                else throw new ArgumentException("Type " + type.Name + " not supported");
            }
            return header;
        }
        private const int DoubleLength = 18;
        private const int DoubleDecimals = 8;
        private const int IntLength = 10;
        private const int IntDecimals = 0;
        private const int StringLength = 255;
        private const int StringDecimals = 0;
        private const int BoolLength = 1;
        private const int BoolDecimals = 0;
        private const int DateLength = 8;
        private const int DateDecimals = 0;

        public void saveDGVasKML(FileInfo kmlFile, String[] infoColumns = null, bool selectedOnly=true) {
           
            if(infoColumns == null) { 
                infoColumns = (from DataGridViewColumn c in this.DataGridView.Columns
                              where c.ValueType != typeof(Byte[]) &&
                                    c.ValueType != typeof(Object)
                              select c.Name).ToArray();
            
            } ;
         CultureInfo englishCulture = CultureInfo.GetCultureInfo("en-GB");
         HashSet<int> locIDs = new HashSet<int>();
         
         try {
                XmlDocument KML = new XmlDocument();
                KML.AppendChild(KML.CreateXmlDeclaration("1.0", "UTF-8", String.Empty));
                XmlElement kmlNode = (XmlElement)KML.AppendChild(KML.CreateElement("kml"));
                kmlNode.SetAttribute("xmlns", "http://www.opengis.net/kml/2.2");
                XmlElement docNode = KML.CreateElement("Document");
                KML.LastChild.AppendChild(docNode);
                // String[] pointInfo = new String[] { "id", "name", "height", "slope", "longitude", "latitude", "notes" };
                StringBuilder SB = new StringBuilder();
                foreach(DataGridViewRow row in this.DataGridView.Rows) {
                    DataGridViewGeometryCell GCell = row.Cells[this.Index] as DataGridViewGeometryCell;
                    if(GCell == null || GCell.Geometry == null) continue;
                    if(selectedOnly && !(row.Selected || GCell.Selected)) continue;

                    IGeometry g = GCell.Geometry;
                    XmlElement placemark = (XmlElement)docNode.AppendChild(KML.CreateElement("Placemark"));
                    placemark.AppendChild(KML.CreateElement("name"));
                    //placemark.LastChild.InnerXml = String.Format("{0}", id);
                    placemark.AppendChild(KML.CreateElement("description"));

                    SB.AppendLine("<![CDATA[");
                    //SB.AppendLine("CORE.LOCATIONS");
                    SB.AppendLine("<table border=\"0\">");
                    foreach(String entry in infoColumns) {
                        if(this.DataGridView.Columns.Contains(entry) &&
                            row.Cells[entry].Value != DBNull.Value) {
                            SB.AppendLine("<tr>");
                            SB.AppendFormat("<td>{0}</td>\n", entry);
                            SB.AppendFormat(englishCulture, "<td>{0}</td>\n",
                                (row.Cells[entry].Value != DBNull.Value)? row.Cells[entry].Value : "");
                            SB.AppendLine("</tr>");
                        }
                    }
                    SB.AppendLine("</table>");
                    SB.AppendLine("]]>");
                    placemark.LastChild.InnerXml = SB.ToString();
                    SB.Remove(0, SB.Length - 1);
                                
                    switch(g.OgcGeometryType){
                        case OgcGeometryType.Point :
                            IPoint p = g as IPoint;
                            placemark.AppendChild(KML.CreateElement("Point"));
                            XmlElement coordinates = (XmlElement)placemark.LastChild.AppendChild(KML.CreateElement("coordinates"));
                            coordinates.InnerXml = String.Format(
                                englishCulture, "{0}, {1}",p.X, p.Y);
                                
                            break;
                        default: break;//nothing
                    }
                                

                                //locIDs.Add(id);
                }
                        
             
               KML.Save(kmlFile.FullName);
            } catch(Exception ex) {
                FormHelper.ShowErrorBox(ex);
            }
            
            
            }



    }

    
    
}
